from django.template import Context, loader, RequestContext
from django.template.loader import get_template
from django.shortcuts import render_to_response, get_object_or_404
from django.http import HttpResponse
from django.contrib.auth.decorators import login_required
from django.contrib.auth.models import User
from django.contrib.auth import logout, login, authenticate
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse
from django.core.serializers import serialize
from django.utils import simplejson
from django import newforms as forms

# Create your views here.
import datetime
from movie.vote.models import Movie

class NewUserForm(forms.Form):
  username = forms.CharField(max_length=30)
  email = forms.EmailField()
  password1 = forms.CharField(max_length=30, widget=forms.PasswordInput, label='Password')
  password2 = forms.CharField(max_length=30, widget=forms.PasswordInput, label='Password (again)')

  def clean(self):
    """Make sure password fields match."""
    if 'password1' in self.cleaned_data and 'password2' in self.cleaned_data:
      if self.cleaned_data['password1'] != self.cleaned_data['password2']:
        raise forms.ValidationError('Passwords do not match')
    return self.cleaned_data

def set_preference(request, name, value):
  request.session[name] = value

def get_preference(request, name, default=None, cast=None):
  pref = default
  if name in request.GET:
    pref = request.GET[name]
  elif name in request.session:
    pref = request.session[name]
  if cast:
    try:
      pref = cast(pref)
    except (TypeError, ValueError):
      pref = default
  return pref

def get_sort_description(value):
  if value.startswith('-'):
    order = 'descending'
    value = value[1:]
  else:
    order = 'ascending'
  if value == 'date_added':
    value = 'addition date'
  return '%s (%s)' % (value, order)
  
def get_movies_for_ui(userid, sort_criteria=None, movie_name=None):
  movies = Movie.objects.extra(select={
    # Plus votes
    'voter_count': 'select count(*) from vote_movie_voters where movie_id = vote_movie.name',
    # Minus votes
    'downvoter_count': 'select count(*) from vote_movie_downvoters where movie_id = vote_movie.name',
    # Has this user voted?
    'voted': 'select count(*) from vote_movie_voters where movie_id = vote_movie.name '
             'and user_id=%s',
    # Has this user downvoted?
    'downvoted': 'select count(*) from vote_movie_downvoters where movie_id = vote_movie.name '
             'and user_id=%s',
    # Number of screenings
    'screenings': 'select count(*) from vote_screening where movie_id = vote_movie.name',
  }, params=[userid, userid])
  if sort_criteria:
    movies = movies.order_by(*sort_criteria)
  if movie_name:
    movies = movies.filter(pk=movie_name)

  for movie in movies:
    screening_stat = ''
    if movie.screenings:
      screening_stat = '/S=%s' % (movie.screenings,)
    movie.tally_detail = '(+%s/-%s%s)' % (movie.voter_count,
                                          movie.downvoter_count,
                                          screening_stat)
  return movies

def movie_to_dict(movie):
  movie_dict = {}
  for field in ('name', 'screenings', 'tally_detail', 'imdb_url',
                'rotten_url', 'metacritic_url', 'voter_count',
                'downvoter_count', 'voted', 'tally', 'downvoted'):
    movie_dict[field] = str(getattr(movie, field))
  return movie_dict

@login_required
def index(request, output=None):
  sort1 = get_preference(request, 'sort1', '-tally')
  sort2 = get_preference(request, 'sort2', 'name')
  if sort1 == '-tally' and sort2 == 'name':
    # Default sort provides link to sort by latest movies
    sort_params = 'sort1=-date_added&sort2=name'
  else:
    # Latest movies sort provides link to sort by tally
    sort_params = 'sort1=-tally&sort2=name'
  set_preference(request, 'sort1', sort1)
  set_preference(request, 'sort2', sort2)
  # Create sorting description
  sort_description = ' and '.join([get_sort_description(sort1), get_sort_description(sort2)])

  sort_criteria = []
  if sort1:
    sort_criteria.append(sort1)
  if sort2:
    sort_criteria.append(sort2)
  
  DEFAULT_START = 0
  DEFAULT_COUNT = 25
  start = get_preference(request, 'start', DEFAULT_START, int)
  count = get_preference(request, 'count', DEFAULT_COUNT, int)
  old_count = get_preference(request, 'old_count', DEFAULT_COUNT, int)
  set_preference(request, 'count', count)

  movies = get_movies_for_ui(request.user.id, sort_criteria)
  movie_count = len(movies)
  if count:
    movies = movies[start:(count + start)]

  if output:
    return HttpResponse(simplejson.dumps([movie_to_dict(x) for x in movies]),
                        mimetype='application/%s' % (str(output),))

  return render_to_response('index.html',
                            {'movies': movies,
                             'sort_params': sort_params,
                             'sort_description': sort_description,
                             'start': start,
                             'count': count,
                             'old_count': old_count,
                             'first': 0,
                             'last': movie_count - max(count, old_count),
                             'next': min(movie_count - count, start + count),
                             'prev': max(0, min(start - count, movie_count - count))
                            },
                            context_instance=RequestContext(request))

@login_required
def voters(request, movie_name):
  movie = get_object_or_404(Movie, pk=movie_name)
  voters = movie.voters.order_by('username')
  downvoters = movie.downvoters.order_by('username')
  for voter in voters:
    voter.weight = movie.get_weight(voter)
  for voter in downvoters:
    voter.weight = movie.get_weight(voter)
  return render_to_response('voters.html', {'movie': movie, 'voters': voters,
                                            'downvoters': downvoters})

@login_required
def update_tallies(request):
  Movie.update_all_tallies()
  return HttpResponseRedirect(request.META.get('HTTP_REFERER',
                              reverse('movie.vote.views.index')))

@login_required
def minus_vote(request, movie_name, output=None):
  movie = get_object_or_404(Movie, pk=movie_name)
  voters = movie.voters.filter(username=request.user.username)
  downvoters = movie.downvoters.filter(username=request.user.username)
  if voters:
    movie.voters.remove(request.user)
  elif not downvoters:
    movie.downvoters.add(request.user)
  movie.update_tally()
  if output:
    movie_dict = movie_to_dict(get_movies_for_ui(request.user.id, movie_name=movie_name)[0])
    return HttpResponse(simplejson.dumps(movie_dict),
                        mimetype='application/%s' % (str(output),))
  return HttpResponseRedirect(request.META.get('HTTP_REFERER',
                              reverse('movie.vote.views.index')))

@login_required
def plus_vote(request, movie_name, output=None):
  movie = get_object_or_404(Movie, pk=movie_name)
  voters = movie.voters.filter(username=request.user.username)
  downvoters = movie.downvoters.filter(username=request.user.username)
  if downvoters:
    movie.downvoters.remove(request.user)
  elif not voters:
    movie.voters.add(request.user)
  movie.update_tally()
  movies = get_movies_for_ui(request.user.id, movie_name=movie_name)
  if output:
    movie_dict = movie_to_dict(get_movies_for_ui(request.user.id, movie_name=movie_name)[0])
    return HttpResponse(simplejson.dumps(movie_dict),
                        mimetype='application/%s' % (str(output),))
  return HttpResponseRedirect(request.META.get('HTTP_REFERER',
                              reverse('movie.vote.views.index')))

def new_user(request):
  if request.method == 'POST':
    form = NewUserForm(request.POST)
    if form.is_valid():
      user = User.objects.create_user(
        form.cleaned_data['username'],
        form.cleaned_data['email'],
        form.cleaned_data['password1'])
      user.save()
      user = authenticate(username=form.cleaned_data['username'],
                          password=form.cleaned_data['password1'])
      login(request, user)
      return HttpResponseRedirect(reverse('movie.vote.views.index'))
  else:
    form = NewUserForm()
  return render_to_response('registration/new_user.html', {'form': form})
